#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<stdlib.h>
#include<sys/wait.h>
#include<string.h>
#define MAXSIZE 128
//这两个作用等同于main函数参数
//shell自己维护的第一张表：命令行参数表
char*myargv[MAXSIZE];//将打散的命令存储于此
int myargc=0;
//分隔符
const char*sep=" ";
//我们shell自己的工作路径
char cwd[MAXSIZE];
//这里我们不做系统调用，只做模拟从环境变量中获取
const char* GetUserName()
{
    char*name=getenv("USER");
    if(name==NULL)
        return "None";
    return name;
}

const char* GetHostName()
{
    char*hostname=getenv("HOSTNAME");
    if(hostname==NULL)
        return "None";
    return hostname;
}
const char* GetPwd()
{
    char*pwdname=getenv("PWD");
    //char*pwdname=getcwd(cwd,sizeof(cwd));
    if(pwdname==NULL)
        return "None";
    return pwdname;
}
void PrintCommandLine()
{
    printf("[%s@%s %s]#",GetUserName(),GetHostName(),GetPwd());//用户名@主机名 当前路径
    fflush(stdout);
}
int GetCommand(char*command_line,int size)
{
    if(fgets(command_line,size,stdin)==NULL)//不用scanf是因为它会默认以空格为分隔符，无法全部截取
        return 0;
    //用户在输入的时候至少按一下回车
    command_line[strlen(command_line)-1]='\0';
    //如果用户输入的是空串，继续输入
    return strlen(command_line);
    // printf("%s\n",command_line);//测试用，现在不需要了
}
int ParseCommand(char*command_line)
{
    myargc = 0;  
    memset(myargv,0,sizeof(myargv));
    //写法1
    //while((myargv[myargc++]=strtok(command_line,sep)));
    //写法2
    myargv[0]=strtok(command_line,sep);
    while((myargv[++myargc]=strtok(NULL,sep)));
    
  //  printf("myargc:%d\n", myargc);
  //  for(int i = 0; i < myargc; ++i)
  //      printf("myargv[%d]:%s\n", i, myargv[i]);
  //  
    return myargc;
}
int ExecuteCommand()
{
    //不能让bash自己执行命令，必须创建子进程进行替换
    pid_t id=fork();
    if(id<0) return -1;
    else if(id==0)
    {
        //子进程
        execvp(myargv[0],myargv);
        exit(0);        
    }
    else
    {
        int status=0;
        //父进程
        pid_t rid =waitpid(id,&status,0);
        if(rid>0)
        {
            printf("等待成功！");
        }
    }
    return 0;
}
//1是内建命令或者已经执行完毕
//0不是内建命令
int CheckBuiltinExecute()
{
    if(strcmp(myargv[0],"cd")==0)
    {
        //内建命令
        if(myargc==2)
        {
            //新的路径为myargv[1]
            chdir(myargv[1]);
            char pwd[1024];
            getcwd(pwd,sizeof(pwd));//获取当前路径
            snprintf(cwd,sizeof(cwd),"PID:%s",pwd);
            putenv(cwd);
        }
        return 1;
    }
    return 0;
}
int main()
{
    char command_line[MAXSIZE]={0};
    //shell本质是一个死循环
    while(1)
    {
        //1、打印命令行
        PrintCommandLine();
        //2、获取用户输入
        if(GetCommand(command_line,sizeof(command_line))==0)//要么输入失败要么字符串为空
            continue;
        printf("%s\n",command_line);
        //3、解析字符串。就是比如"ls -a -l"就要转化为"ls""-a""-l"命令解析器,对用户输入的命令做处理
        ParseCommand(command_line);
        sleep(1);
        //4、判断该命令由哪个进程执行
        if(CheckBuiltinExecute())
            continue;
        //5、子进程执行该命令
        ExecuteCommand();        
    }
    return 0;
}
